#include <string.h>
#include <stdio.h>
#include "air105.h"

/* Private function prototypes -----------------------------------------------*/
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

#define SPI_MODE_POLLING 1              // 轮询模式
#define SPI_MODE_INTERRUPT 2            // 中断模式
#define SPI_MODE_SEL SPI_MODE_POLLING // 选择模式

#define SEND_BUF_SIZE 256
#define RECE_BUF_SIZE 256

uint8_t send_buf[SEND_BUF_SIZE] = {0x00};
uint8_t rece_buf[RECE_BUF_SIZE] = {0x00};

uint32_t send_buf_index = 0;
uint32_t rece_buf_index = 0;

void NVIC_Configuration(void);
void SPI_Configuration(void);
void UART_Configuration(void);

static void DataPrintf(uint8_t *buf, uint32_t bufsize)
{
    // 打印数据
    uint32_t j;
    for (j = 0; j < bufsize; j++)
    {
        printf("%02X ", buf[j]);
        if ((j + 1) % 16 == 0)
            printf("\r");
    }
}

#if (SPI_MODE_SEL == SPI_MODE_INTERRUPT) // 中断模式
int main(void)
{
    uint32_t i;

    SYSCTRL_ClocksTypeDef clocks;
    SYSCTRL_PLLConfig(SYSCTRL_PLL_204MHz);                                                                        // 设置PLL时钟
    SYSCTRL_GetClocksFreq(&clocks);                                                                               // 获取时钟频率
    SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_UART0 | SYSCTRL_APBPeriph_GPIO | SYSCTRL_APBPeriph_SPI2, ENABLE); // 使能UART0和SPI2时钟
    SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_UART0 | SYSCTRL_APBPeriph_SPI2, ENABLE);                          // 复位UART0和SPI2

    NVIC_Configuration();
    SPI_Configuration();
    SPI_ITConfig(SPIM2, SPI_IT_RXF, ENABLE);

    UART_Configuration();
    printf("LuatOS SCPU SPI Master Tx And Rx Demo V1.0.\n");
    printf("中断模式\n");
    // Send Data Init 0x50 To 0x5F
    printf("Send Data Init \n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        send_buf[i] = (uint8_t)((i & 0x0F) | 0x50);
    }
    memset(rece_buf, 0, sizeof(rece_buf));
    DataPrintf(send_buf, SEND_BUF_SIZE);
    printf("Send Data Buf is 0x50~0x5F\n");
    printf("Reve Data Buf is all 0x00\n");

    // 清空接收缓冲区
    printf("Rx FIFO Clean\n");
    while (SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE)) // 获取接收缓冲区非空标志
        SPI_ReceiveData(SPIM2);                     // 清空接收缓冲区

    printf("Master Send and Reve Start\n\n");
    SPI_ITConfig(SPIM2, SPI_IT_TXE, ENABLE); // 开启发送中断
    while (send_buf_index)                   // 等待发送完成
        ;

    printf("Master Send and Reve End\n");
    printf("Send Data Buf\n");
    DataPrintf(send_buf, SEND_BUF_SIZE);
    printf("Reve Data Buf\n");
    DataPrintf(rece_buf, RECE_BUF_SIZE);

    // Send Data Init 0x60 To 0x6F
    printf("Send Data Init \n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        send_buf[i] = (uint8_t)((i & 0x0F) | 0x60);
    }
    memset(rece_buf, 0, sizeof(rece_buf));

    printf("Send Data Buf is 0x60~0x6F\n");
    printf("Reve Data Buf is all 0x00\n");

    // Clear RX FIFO
    printf("Rx FIFO Clean\n");
    while (SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
        SPI_ReceiveData(SPIM2);

    printf("Master Send and Reve Start\n\n");
    SPI_ITConfig(SPIM2, SPI_IT_TXE, ENABLE);
    while (send_buf_index)
        ;

    printf("Master Send and Reve End\n");
    printf("Send Data Buf\n");
    DataPrintf(send_buf, SEND_BUF_SIZE);
    printf("Reve Data Buf\n");
    DataPrintf(rece_buf, RECE_BUF_SIZE);

    // Send Data Init 0x70 To 0x7F
    printf("Send Data Init \n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        send_buf[i] = (uint8_t)((i & 0x0F) | 0x70);
    }
    memset(rece_buf, 0, sizeof(rece_buf));

    printf("Send Data Buf is 0x70~0x7F\n");
    printf("Reve Data Buf is all 0x00\n");

    // Clear RX FIFO
    printf("Rx FIFO Clean\n");
    while (SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
        SPI_ReceiveData(SPIM2);

    printf("Master Send and Reve Start\n\n");
    SPI_ITConfig(SPIM2, SPI_IT_TXE, ENABLE);
    while (send_buf_index)
        ;

    printf("Master Send and Reve End\n");
    printf("Send Data Buf\n");
    DataPrintf(send_buf, SEND_BUF_SIZE);
    printf("Reve Data Buf\n");
    DataPrintf(rece_buf, RECE_BUF_SIZE);

    while (1)
        ;
}

#elif (SPI_MODE_SEL == SPI_MODE_POLLING) // 轮询模式

int main(void)
{
    uint32_t i;
    SYSCTRL_ClocksTypeDef clocks;
    SYSCTRL_PLLConfig(SYSCTRL_PLL_204MHz);                                                                        // 设置PLL时钟
    SYSCTRL_GetClocksFreq(&clocks);                                                                               // 获取时钟频率
    SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_UART0 | SYSCTRL_APBPeriph_GPIO | SYSCTRL_APBPeriph_SPI2, ENABLE); // 使能UART0和SPI2时钟
    SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_UART0 | SYSCTRL_APBPeriph_SPI2, ENABLE);                          // 复位UART0和SPI2

    SPI_Configuration();  // SPI配置
    UART_Configuration(); // UART配置
    printf("LuatOS AIR105 SPI Master Tx And Rx Demo V1.0.\n");

    // Send Data Init 0x50 To 0x5F
    printf("Send Data Init \n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        send_buf[i] = (uint8_t)((i & 0x0F) | 0x50);
    }
    memset(rece_buf, 0, sizeof(rece_buf));

    printf("Send Data Buf is 0x50~0x5F\n");
    printf("Reve Data Buf is all 0x00\n");

    // Clear RX FIFO
    printf("Rx FIFO Clean\n");
    while (SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
        SPI_ReceiveData(SPIM2);

    printf("Master Send and Reve Start\n\n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        SPI_SendData(SPIM2, send_buf[i]);
        while (RESET == SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
            ;
        rece_buf[i] = SPI_ReceiveData(SPIM2);
    }

    printf("Master Send and Reve End\n");
    printf("Send Data Buf\n");
    DataPrintf(send_buf, SEND_BUF_SIZE);
    printf("Reve Data Buf\n");
    DataPrintf(rece_buf, RECE_BUF_SIZE);

    // Send Data Init 0x60 To 0x6F
    printf("Send Data Init \n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        send_buf[i] = (uint8_t)((i & 0x0F) | 0x60);
    }
    memset(rece_buf, 0, sizeof(rece_buf));

    printf("Send Data Buf is 0x60~0x6F\n");
    printf("Reve Data Buf is all 0x00\n");

    // Clear RX FIFO
    printf("Rx FIFO Clean\n");
    while (SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
        SPI_ReceiveData(SPIM2);

    printf("Master Send and Reve Start\n\n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        SPI_SendData(SPIM2, send_buf[i]);
        while (RESET == SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
            ;
        rece_buf[i] = SPI_ReceiveData(SPIM2);
    }

    printf("Master Send and Reve End\n");
    printf("Send Data Buf\n");
    DataPrintf(send_buf, SEND_BUF_SIZE);
    printf("Reve Data Buf\n");
    DataPrintf(rece_buf, RECE_BUF_SIZE);

    // Send Data Init 0x70 To 0x7F
    printf("Send Data Init \n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        send_buf[i] = (uint8_t)((i & 0x0F) | 0x70);
    }
    memset(rece_buf, 0, sizeof(rece_buf));

    printf("Send Data Buf is 0x70~0x7F\n");
    printf("Reve Data Buf is all 0x00\n");

    // Clear RX FIFO
    printf("Rx FIFO Clean\n");
    while (SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
        SPI_ReceiveData(SPIM2);

    printf("Master Send and Reve Start\n\n");
    for (i = 0; i < SEND_BUF_SIZE; i++)
    {
        SPI_SendData(SPIM2, send_buf[i]);
        while (RESET == SPI_GetFlagStatus(SPIM2, SPI_FLAG_RXNE))
            ;
        rece_buf[i] = SPI_ReceiveData(SPIM2);
    }

    printf("Master Send and Reve End\n");
    printf("Send Data Buf\n");
    DataPrintf(send_buf, SEND_BUF_SIZE);
    printf("Reve Data Buf\n");
    DataPrintf(rece_buf, RECE_BUF_SIZE);

    while (1)
        ;
}
#endif

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_SetPriorityGrouping(NVIC_PriorityGroup_3);

    NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);
}

void SPI_Configuration(void)
{
    SPI_InitTypeDef SPI_InitStructure;

    // SPI2
    GPIO_PinRemapConfig(GPIOB, GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5, GPIO_Remap_0);

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;        // SPI配置为双线全双工
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                         // SPI发送接收8位帧结构
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                // 串行同步时钟的空闲状态为低电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                              // 串行同步时钟的第1个跳变沿（上升或下降）数据被采样
    SPI_InitStructure.SPI_NSS = SPI_NSS_0;                                    // NSS信号由硬件（NSS管脚）管理
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;      // 波特率预分频值为256
    SPI_InitStructure.SPI_RXFIFOFullThreshold = SPI_RXFIFOFullThreshold_1;    // 接收FIFO满阈值为1
    SPI_InitStructure.SPI_TXFIFOEmptyThreshold = SPI_TXFIFOEmptyThreshold_10; // 发送FIFO空阈值为10

    SPI_Init(SPIM2, &SPI_InitStructure);
    SPI_Cmd(SPIM2, ENABLE);
}

void UART_Configuration(void)
{
    UART_InitTypeDef UART_InitStructure;

    // UART0
    GPIO_PinRemapConfig(GPIOA, GPIO_Pin_0 | GPIO_Pin_1, GPIO_Remap_0);

    UART_InitStructure.UART_BaudRate = 115200;
    UART_InitStructure.UART_WordLength = UART_WordLength_8b;
    UART_InitStructure.UART_StopBits = UART_StopBits_1;
    UART_InitStructure.UART_Parity = UART_Parity_No;

    UART_Init(UART0, &UART_InitStructure);
}

// Retarget Printf
int SER_PutChar(int ch)
{
    while (!UART_IsTXEmpty(UART0))
        ;
    UART_SendData(UART0, (uint8_t)ch);

    return ch;
}

int fputc(int c, FILE *f)
{
    /* Place your implementation of fputc here */
    /* e.g. write a character to the USART */
    if (c == '\n')
    {
        SER_PutChar('\r');
    }
    return (SER_PutChar(c));
}

#ifdef USE_FULL_ASSERT

/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

    /* Infinite loop */
    while (1)
    {
    }
}
#endif
